#ifndef __NETWORK_FRAME_H__
#define __NETWORK_FRAME_H__
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h> 
#include <fcntl.h>
#include <time.h>  
#include <sys/socket.h>  
#include <sys/types.h>  
#include <netinet/in.h>  
#include <errno.h>

#ifdef __cplusplus
extern "C" {
#endif

struct list_head
{
    struct list_head* next;
    struct list_head* prev;
};

struct conn_cb_t
{
    /*
     * Handle connection incoming message
     */
    void (*func)(struct conn_t* c, const char* buf, ssize_t len);
    
    /*
     * Optional: called on `EOF' received.
     */
    void (*on_close)(struct conn_t* c);

    /*
     * Optional: called on receive error (-1 returned)
     */
    void (*on_error)(struct conn_t* c);
};

/*
 * represent a connection point
 */
struct conn_t
{
    int fd;
    struct sockaddr_in addr;
    struct conn_cb_t* cb;
    struct sock_io_ops* ops;
    struct conn_context* ctxt;
    struct list_head list;
};

typedef struct sock_io_ops 
{
    int (*connect)(struct conn_t* c, struct sockaddr_in* addr);
    ssize_t (*recvive)(struct conn_t* c, void *buf, size_t len);
    ssize_t (*send)(struct conn_t* c, const void *buf, size_t len);
    ssize_t (*sendto)(struct conn_t* c, const void *buf, size_t len, const struct sockaddr *dest_addr, socklen_t addrlen);
} conn_io_ops;

typedef struct conn_context
{
    struct {
        int listen_fd;
        struct conn_cb_t* cb;
        struct sock_io_ops* sock_ops;
    } srv;

    struct {
        int maxfd;
        int nr_fd;
        fd_set rset;
        struct list_head list;
        int nr_conn;
    } sop;  
} conn_ctxt_t;

int conn_context_init(struct conn_context* ctxt);
int conn_context_destory(struct conn_context* ctxt);

/*
 * Init internal data struct
 * Return: On success, 0 is returne.  On error, -1 is returned
 */
int tcp_server_init(struct conn_context* ctxt, struct sockaddr_in* addr, struct conn_cb_t* cb);
int server_shutdown(struct conn_context* ctxt);

/*
 * Make a new connection to `addr'
 * Return: On success, conn_t struct is returned.  On error, NULL is returned
 */
struct conn_t* make_tcpconn_to(struct conn_context* ctxt, struct sockaddr_in* addr, struct conn_cb_t* cb);
struct conn_t* make_udpconn_to(struct conn_context* ctxt, struct sockaddr_in* addr, struct conn_cb_t* cb);
int bind_local_address(struct conn_t* c, struct sockaddr_in* addr);
int release_connection(struct conn_t* c);

int send_msg(struct conn_t* c, const char* buf, ssize_t len);
int send_msg_to(struct conn_t* c, const char* buf, ssize_t len, const struct sockaddr *dest_addr, socklen_t addrlen);
int recv_msg(struct conn_t* c, char* buf, ssize_t len);

int main_loop(struct conn_context* ctxt);

#ifdef __cplusplus
}
#endif

#endif /* __NETWORK_FRAME_H__ */
